#pragma once

using namespace System;
using namespace NUnit::Framework;
using namespace LatoolNet;

namespace LatoolNetTest {

	[TestFixture]
	public ref class ComplexHermitianMatrixTest {
	public:

		[Test]
		void TestPositiveDefiniteFactorizeAndSolve() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			a[0, 0] = Complex(3.23, 0.00);

			a[1, 0] = Complex(1.51, 1.92);
			a[1, 1] = Complex(3.58, 0.00);

			a[2, 0] = Complex(1.90, -0.84);
			a[2, 1] = Complex(-0.23, -1.11);
			a[2, 2] = Complex(4.09, 0.00);

			a[3, 0] = Complex(0.42, -2.50);
			a[3, 1] = Complex(-1.18, -1.37);
			a[3, 2] = Complex(2.33, 0.14);
			a[3, 3] = Complex(4.29, 0.00);

			ComplexMatrix ^ b = gcnew ComplexMatrix(rownum, 1);

			b[0, 0] = Complex(3.93, -6.14);
			b[1, 0] = Complex(6.17, 9.42);
			b[2, 0] = Complex(-7.17, -21.83);
			b[3, 0] = Complex(1.99, -14.38);

			//LUFactorization::Factorize(a);
			LinearEquation::Factorize(a);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			Assert::AreEqual(1.0000, b[0, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[0, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(0.0000, b[1, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(3.0000, b[1, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-4.0000, b[2, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-5.0000, b[2, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[3, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(1.0000, b[3, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");

		};

		[Test]
		void TestPositiveDefiniteSolve() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			a[0, 0] = Complex(3.23, 0.00);

			a[1, 0] = Complex(1.51, 1.92);
			a[1, 1] = Complex(3.58, 0.00);

			a[2, 0] = Complex(1.90, -0.84);
			a[2, 1] = Complex(-0.23, -1.11);
			a[2, 2] = Complex(4.09, 0.00);

			a[3, 0] = Complex(0.42, -2.50);
			a[3, 1] = Complex(-1.18, -1.37);
			a[3, 2] = Complex(2.33, 0.14);
			a[3, 3] = Complex(4.29, 0.00);

			ComplexMatrix ^ b = gcnew ComplexMatrix(rownum, 1);

			b[0, 0] = Complex(3.93, -6.14);
			b[1, 0] = Complex(6.17, 9.42);
			b[2, 0] = Complex(-7.17, -21.83);
			b[3, 0] = Complex(1.99, -14.38);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			Assert::AreEqual(1.0000, b[0, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[0, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(0.0000, b[1, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(3.0000, b[1, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-4.0000, b[2, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(-5.0000, b[2, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[3, 0].Real, 1e-10, "Test: Positive-definite Factorize And Solve.");
			Assert::AreEqual(1.0000, b[3, 0].Imag, 1e-10, "Test: Positive-definite Factorize And Solve.");

		};

		[Test]
		void TestIndefiniteFactorizeAndSolve() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			
			a[0, 0] = Complex(-1.36, 0.00);
			a[0, 1] = Complex(1.58, 0.90);
			a[0, 2] = Complex(2.21, -0.21);
			a[0, 3] = Complex(3.91, 1.50);

			a[1, 1] = Complex(-8.87, 0.00);
			a[1, 2] = Complex(-1.84, -0.03);
			a[1, 3] = Complex(-1.78, 1.18);

			a[2, 2] = Complex(-4.63, 0.00);
			a[2, 3] = Complex(0.11, 0.11);

			a[3, 3] = Complex(-1.84, 0.00);

			ComplexMatrix ^ b = gcnew ComplexMatrix(rownum, 1);

			b[0, 0] = Complex(7.79, 5.48);
			b[1, 0] = Complex(-0.77, -16.05);
			b[2, 0] = Complex(-9.58, 3.88);
			b[3, 0] = Complex(2.98, -10.18);

			//LUFactorization::Factorize(a);
			LinearEquation::Factorize(a);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			Assert::AreEqual(1.0000, b[0, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[0, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[1, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[1, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(3.0000, b[2, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-2.0000, b[2, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[3, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(1.0000, b[3, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");

		};

		[Test]
		void TestIndefiniteSolve() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			
			a[0, 0] = Complex(-1.36, 0.00);
			a[0, 1] = Complex(1.58, 0.90);
			a[0, 2] = Complex(2.21, -0.21);
			a[0, 3] = Complex(3.91, 1.50);

			a[1, 1] = Complex(-8.87, 0.00);
			a[1, 2] = Complex(-1.84, -0.03);
			a[1, 3] = Complex(-1.78, 1.18);

			a[2, 2] = Complex(-4.63, 0.00);
			a[2, 3] = Complex(0.11, 0.11);

			a[3, 3] = Complex(-1.84, 0.00);

			ComplexMatrix ^ b = gcnew ComplexMatrix(rownum, 1);

			b[0, 0] = Complex(7.79, 5.48);
			b[1, 0] = Complex(-0.77, -16.05);
			b[2, 0] = Complex(-9.58, 3.88);
			b[3, 0] = Complex(2.98, -10.18);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			Assert::AreEqual(1.0000, b[0, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[0, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-1.0000, b[1, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[1, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(3.0000, b[2, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(-2.0000, b[2, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(2.0000, b[3, 0].Real, 1e-10, "Test: Indefinite Factorize And Solve.");
			Assert::AreEqual(1.0000, b[3, 0].Imag, 1e-10, "Test: Indefinite Factorize And Solve.");

		};

		[Test]
		void TestPositiveDefiniteInvert() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			a[0, 0] = Complex(3.23, 0.00);

			a[1, 0] = Complex(1.51, 1.92);
			a[1, 1] = Complex(3.58, 0.00);

			a[2, 0] = Complex(1.90, -0.84);
			a[2, 1] = Complex(-0.23, -1.11);
			a[2, 2] = Complex(4.09, 0.00);

			a[3, 0] = Complex(0.42, -2.50);
			a[3, 1] = Complex(-1.18, -1.37);
			a[3, 2] = Complex(2.33, 0.14);
			a[3, 3] = Complex(4.29, 0.00);

			ComplexMatrix^ ainv = a->Clone()->Inv();

			ComplexMatrix^ ainvinv = ainv->Clone()->Inv();


			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(a[i, j].Real, ainvinv[i, j].Real, 1e-10, "Test: Positive-definite Invert.");
					Assert::AreEqual(a[i, j].Imag, ainvinv[i, j].Imag, 1e-10, "Test: Positive-definite Invert.");
				}
			}

		};
		[Test]
		void TestIndefiniteInvert() {
			
			int rownum = 4;
			int colnum = 4;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum, MatrixType::ComplexHermitian);
			
			a[0, 0] = Complex(-1.36, 0.00);
			a[0, 1] = Complex(1.58, 0.90);
			a[0, 2] = Complex(2.21, -0.21);
			a[0, 3] = Complex(3.91, 1.50);

			a[1, 1] = Complex(-8.87, 0.00);
			a[1, 2] = Complex(-1.84, -0.03);
			a[1, 3] = Complex(-1.78, 1.18);

			a[2, 2] = Complex(-4.63, 0.00);
			a[2, 3] = Complex(0.11, 0.11);

			a[3, 3] = Complex(-1.84, 0.00);

			ComplexMatrix ^ ainv = a->Clone()->Inv();

			ComplexMatrix ^ ainvinv = ainv->Clone()->Inv();

			//Console::WriteLine(uni->ToString());

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(a[i, j].Real, ainvinv[i, j].Real, 1e-10, "Test: Indefinite Invert.");
					Assert::AreEqual(a[i, j].Imag, ainvinv[i, j].Imag, 1e-10, "Test: Indefinite Invert.");						
				}
			}

		
		};

	};
}
